import { AppTask } from "../../app.task.class";
import { to } from "../../../utils/cmm.util";
import { AppCache } from "../../../utils/cache.util";
import fs from "node:fs";
import FormData from "form-data";
import { logger } from "../../../configs/log.config";
import { V3proAlertMessageFile, V3proSubjectMessage } from "../../v3pro-task/model/v3pro.model";
import { srUploadFileApi } from "../../../api/sr-api/sr.api";

/**
 * 文件上传任务
 */
export class SrHttpUploadFileTask extends AppTask {
  static readonly FILE_CACHE = new AppCache("10d");

  /**
   * 构造函数
   * @param __cache 缓存
   * @param __message
   * @param __successCallback 成功回调
   * @param __failCallback 失败回调
   */
  constructor(
    private __cache: AppCache,
    private __message: V3proSubjectMessage,
    private __successCallback = (res: V3proAlertMessageFile[]) => {},
    private __failCallback = (e: Error) => {},
  ) {
    super();
    this.__files = this.__message.files!;
  }

  private __files: V3proAlertMessageFile[];

  __pause(): Promise<boolean> {
    return Promise.resolve(false);
  }

  __restore(): Promise<boolean> {
    return Promise.resolve(false);
  }

  /**
   * 执行任务
   */
  async __run(): Promise<void> {
    if (!this.__files || this.__files.length === 0 || !this.__message.needUploadFile) {
      return this.__successCallback([]);
    }
    const uploads = this.__files.map(
      (info) =>
        new Promise<V3proAlertMessageFile>((resolve, reject) =>
          this.__uploadFile(resolve, reject, info),
        ),
    );
    const [err, res] = await to(Promise.all(uploads));
    if (err) {
      return this.__failCallback(err);
    }
    if (res!.length === 0) return this.__successCallback([]);
    if (this.isStopped()) return this.__failCallback(new Error("任务被终止"));
    this.__successCallback(res!);
  }

  /**
   * 上传重试
   * @param resolve
   * @param reject
   * @param info 文件描述信息
   * @param retry 重试次数
   */
  private async __uploadFile(
    resolve: any,
    reject: any,
    info: V3proAlertMessageFile,
    retry = 3,
  ): Promise<V3proAlertMessageFile> {
    if (this.isStopped()) return reject(new Error("任务被终止"));
    if (this.__cache.has(info.hash)) {
      info.id = this.__cache.get(info.hash);
      logger.info("文件hash存在，跳过上传：[id] %s, [hash] %s", info.id, info.hash);
      return resolve(info);
    }
    const [err, res] = await to(this.__uploadHandler(info));
    if (err) {
      logger.error("文件上传失败，剩余重试次数：%d, 错误原因：%s", retry, err);
      if (retry > 0) return this.__uploadFile(resolve, reject, info, retry - 1);
      return reject(err?.message || err);
    }
    if (res!.id) this.__cache.set(info.hash, res!.id);
    return resolve(res);
  }

  /**
   * 具体上传逻辑
   * @param info
   * @private
   */
  private async __uploadHandler(info: V3proAlertMessageFile) {
    const formData = new FormData();
    formData.append("file", fs.createReadStream(info.file!.name), info.fileName);
    logger.info("开始上传文件[%s]: %s", info.fileName, info.file!.name);
    const [err, res] = await to(
      srUploadFileApi(this.__message.screenId!, formData, this.__addCancelToken()),
    );
    if (err) return Promise.reject(err?.message || err);
    logger.info("文件上传成功[%s]: %s ", info.fileName, res!.id);
    info.id = res!.id;
    return info;
  }

  /**
   * 停止任务
   */
  async __stop(): Promise<boolean> {
    return true;
  }
}
